package com.heima.search.service.impl;

import com.alibaba.fastjson2.JSON;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.search.dto.UserSearchDto;
import com.heima.model.user.pojos.ApUser;
import com.heima.search.service.ApUserSearchService;
import com.heima.search.service.ArticleSearchService;
import com.heima.utils.thread.AppThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;


@Service
@Slf4j
public class ArticleSearchServiceImpl implements ArticleSearchService {
    /**
     * ES文章分页搜索
     */
    @Autowired
    private RestHighLevelClient restHighLevel;
    @Autowired
    private ApUserSearchService  apUserSearchService;
    @Override
    public ResponseResult ArticleSearch(UserSearchDto dto) throws IOException {
        /**
         * 首先检查传入的参数是否有效，如果无效则返回错误响应。
         * 创建SearchRequest对象，指定要搜索的索引为app_info_article。
         * 使用SearchSourceBuilder构建查询条件。
         * 构建布尔查询条件，包括：
         * 使用QueryStringQueryBuilder进行关键字的分词查询，查询字段包括title和content。
         * 使用RangeQueryBuilder过滤发布时间小于mindate的数据。
         * 设置分页参数，从0开始，大小为dto.getPageSize()。
         * 设置按照发布时间倒序排序。
         * 设置高亮显示，只对title字段进行高亮。
         * 将查询条件设置到searchRequest中，并执行搜索。
         * 处理搜索结果，将每个搜索命中的源数据转换为Map，并处理高亮显示的标题。
         * 将结果封装到ResponseResult中并返回。
         */
        // 校验参数
        if(dto==null|| StringUtils.isBlank(dto.getSearchWords())){
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_INVALID);
        }
        //异步调用 保存搜索记录
        ApUser user = AppThreadLocalUtil.getUser();
        if(user!=null&& dto.getFromIndex()==0){
            apUserSearchService.insert(dto.getSearchWords(),user.getId());
        }
        //设置查询的索引对象
        SearchRequest searchRequest = new SearchRequest("app_info_article");
        //设置查询构造器
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //构建布尔查询
        BoolQueryBuilder booledQuery = QueryBuilders.boolQuery();
        //设置分词之后的查询
        QueryStringQueryBuilder queryStringQueryBuilder = QueryBuilders.queryStringQuery(dto.getSearchWords()).field("title").field("content").defaultOperator(Operator.OR);
        booledQuery.must(queryStringQueryBuilder);
        //查询小于mindate的数据
        RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("publishTime").lt(dto.getMinBehotTime().getTime());
        booledQuery.filter(rangeQueryBuilder);

        //分页查询
        sourceBuilder.from(0);
        sourceBuilder.size(dto.getPageSize());
        //按照发布时间倒序查询
        sourceBuilder.sort("publishTime", SortOrder.DESC);
        //设置标题高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("title");
        highlightBuilder.preTags("<font style='color:red;font-size:inherit;'>");
        highlightBuilder.postTags("</font>");
        sourceBuilder.highlighter(highlightBuilder);

        sourceBuilder.query(booledQuery);
        searchRequest.source(sourceBuilder);
        //得到响应
        SearchResponse searchResponse = restHighLevel.search(searchRequest, RequestOptions.DEFAULT);
        //处理结果，封装
        List<Map> list=new ArrayList<>();
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            String string = hit.getSourceAsString();
            Map map = JSON.parseObject(string, Map.class);
            if(hit.getHighlightFields()!=null&& hit.getHighlightFields().size()>0){
                Text[] titles = hit.getHighlightFields().get("title").getFragments();
                String join = StringUtils.join(titles);
                //高亮标题
                map.put("h_title",join);
            }else {
                //非高亮标题
                map.put("h_title",map.get("title"));
            }
            list.add(map);
        }
        return ResponseResult.okResult(list);

    }

}
